package at.fhooe.mcm.view;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.OutputStream;

import javax.swing.JButton;

import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

import java.util.ArrayList;

import at.fhooe.mcm.logic.core.Core;

import at.fhooe.mcm.logic.event.Event;
import at.fhooe.mcm.logic.event.EventListener;
import at.fhooe.mcm.logic.event.EventManager;

import at.fhooe.mcm.logic.network.events.PeerConnectedEvent;
import at.fhooe.mcm.logic.network.events.PeerDisconnectedEvent;

import at.fhooe.mcm.logic.sensors.events.SensorChangedEvent;
import at.fhooe.mcm.logic.sensors.events.SensorCreatedEvent;
import at.fhooe.mcm.logic.sensors.events.SensorDestroyedEvent;
import at.fhooe.mcm.logic.sensors.events.SensorDetachEvent;
import at.fhooe.mcm.logic.sensors.events.SensorRequestEvent;
import at.fhooe.mcm.logic.sensors.events.SensorResponseEvent;
import at.fhooe.mcm.logic.sensors.events.SensorUpdatedEvent;

import at.fhooe.mcm.logic.dataexport.SensorSerializationEvent;
import at.fhooe.mcm.logic.dataexport.SensorSerializationEvent.Mode;

public class ManagementView implements EventListener
{

	private JTextArea m_consoleArea;
	private JList m_clientList;
	private JList				m_sensorList;
	private JFrame				m_frame;
	private Core				m_core		= null;
	private ArrayList<String>	m_sensors	= new ArrayList<String>();
	private DefaultListModel	m_listModel	= new DefaultListModel();
	private DefaultListModel	m_clientListModel	= new DefaultListModel();

	/**
	 * Create the application
	 */
	public ManagementView(Core _c)
	{
		m_core = _c;

		createContents();
		EventManager.getInstance(m_core).addListener(this, SensorCreatedEvent.TYPE);
		EventManager.getInstance(m_core).addListener(this, SensorUpdatedEvent.TYPE);
		EventManager.getInstance(m_core).addListener(this, SensorDestroyedEvent.TYPE);
		EventManager.getInstance(m_core).addListener(this, SensorChangedEvent.TYPE);
		EventManager.getInstance(m_core).addListener(this, SensorResponseEvent.TYPE);
		EventManager.getInstance(m_core).addListener(this, PeerConnectedEvent.TYPE);
		EventManager.getInstance(m_core).addListener(this, PeerDisconnectedEvent.TYPE);
		//redirectSystemStreams();
		
	}

	public void show() 
	{
		
		m_frame.setResizable(false);
		m_frame.setVisible(true);
	}
	
	private void addSensorToList(String _id, String _name)
	{
		m_sensors.add(_id);
		m_listModel.add(m_listModel.size(), _name);
	}

	private void removeSensorFromList(String _name)
	{
		int idx = m_sensors.indexOf(_name);
		m_sensors.remove(idx);
		m_listModel.remove(idx);
	}

	/**
	 * Initialize the contents of the frame
	 */
	private void createContents()
	{
		m_frame = new JFrame();
		m_frame.getContentPane().setFocusable(false);
		m_frame.setTitle("Sensor Manager");
		m_frame.getContentPane().setLayout(null);
		m_frame.setBounds(100, 100, 563, 502);
		m_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		final JButton createButton = new JButton();
		createButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(final ActionEvent e)
			{
				new EditView(m_core);
			}
		});
		createButton.setText("Create");
		createButton.setBounds(220, 123, 113, 26);
		m_frame.getContentPane().add(createButton);

		final JLabel sensorsLabel = new JLabel();
		sensorsLabel.setText("Sensors");
		sensorsLabel.setBounds(10, 23, 66, 16);
		m_frame.getContentPane().add(sensorsLabel);

		final JButton editButton = new JButton();
		editButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(final ActionEvent arg0)
			{
				try
				{
				SensorRequestEvent rse = new SensorRequestEvent(m_sensors.get(m_sensorList.getSelectedIndex()));
				EventManager.getInstance(m_core).enqueueEvent(rse);
				}
				catch(ArrayIndexOutOfBoundsException _aioobe)
				{
					JOptionPane.showMessageDialog(m_frame, "Please select a Sensor first", "entry check failed", JOptionPane.OK_OPTION);
					return;
				}
			}
		});
		editButton.setText("Edit");
		editButton.setBounds(220, 155, 113, 26);
		m_frame.getContentPane().add(editButton);

		final JButton deleteButton = new JButton();
		deleteButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(final ActionEvent arg0)
			{
				SensorDetachEvent event = new SensorDetachEvent(m_sensors.get(m_sensorList.getSelectedIndex()));
				EventManager.getInstance(m_core).enqueueEvent(event);
			}
		});
		deleteButton.setText("Delete");
		deleteButton.setBounds(220, 187, 113, 26);
		m_frame.getContentPane().add(deleteButton);

		final JButton loadsensorsButton = new JButton();
		loadsensorsButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(final ActionEvent arg0)
			{
				SensorSerializationEvent sse = new SensorSerializationEvent(Mode.SERIALIZE);
				EventManager.getInstance(m_core).enqueueEvent(sse);
			}
		});
		loadsensorsButton.setText("LoadSensors");
		loadsensorsButton.setBounds(220, 59, 113, 26);
		m_frame.getContentPane().add(loadsensorsButton);

		final JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(10, 47, 163, 266);
		m_frame.getContentPane().add(scrollPane);

		m_sensorList = new JList(m_listModel);
		m_sensorList.setFocusable(false);
		scrollPane.setViewportView(m_sensorList);

		final JButton saveSensorsButton = new JButton();
		saveSensorsButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(final ActionEvent arg0)
			{
				SensorSerializationEvent sse = new SensorSerializationEvent(Mode.DESERIALIZE);
				EventManager.getInstance(m_core).enqueueEvent(sse);
			}
		});
		saveSensorsButton.setText("Save Sensors");
		saveSensorsButton.setBounds(220, 91, 113, 26);
		m_frame.getContentPane().add(saveSensorsButton);

		final JScrollPane scrollPane_2 = new JScrollPane();
		scrollPane_2.setBounds(10, 319, 527, 135);
		m_frame.getContentPane().add(scrollPane_2);

		m_consoleArea = new JTextArea();
		scrollPane_2.setViewportView(m_consoleArea);

		final JScrollPane scrollPane_1 = new JScrollPane();
		scrollPane_1.setBounds(374, 47, 163, 266);
		m_frame.getContentPane().add(scrollPane_1);

		m_clientList = new JList(m_clientListModel);
		m_clientList.setFocusable(false);
		scrollPane_1.setViewportView(m_clientList);
	}

	@Override
	public void handleEvent(Event _event)
	{
		if (_event.getType().equals(SensorCreatedEvent.TYPE))
		{
			SensorCreatedEvent sce = (SensorCreatedEvent) _event;
			addSensorToList(sce.getSensorID(), sce.getSensorName());
		}
		else if (_event.getType().equals(SensorDestroyedEvent.TYPE))
		{
			SensorDestroyedEvent sde = (SensorDestroyedEvent) _event;
			removeSensorFromList(sde.getSensorID());
		}
		else if (_event.getType().equals(SensorChangedEvent.TYPE))
		{
			SensorChangedEvent sce = (SensorChangedEvent) _event;
			m_listModel.remove(m_sensors.indexOf(sce.getSensorID()));
			m_listModel.add(m_sensors.indexOf(sce.getSensorID()), sce.getName());
		}
		else if (_event.getType().equals(SensorResponseEvent.TYPE))
		{
			new EditView(m_core, (SensorResponseEvent) _event);
		}
		else if (_event.getType().equals(PeerConnectedEvent.TYPE))
		{
			PeerConnectedEvent peerConnected = (PeerConnectedEvent) _event;
			m_clientListModel.addElement(peerConnected.getPeer().getAddress().toString());
		}
		else if (_event.isOfType(PeerDisconnectedEvent.TYPE))
		{
			PeerDisconnectedEvent peerDisconnected = (PeerDisconnectedEvent) _event;
			m_clientListModel.removeElement(peerDisconnected.getPeer().getAddress().toString());
		}
	}
	private void updateTextArea(final String text) {
	    SwingUtilities.invokeLater(new Runnable() {
	      public void run() {
	        m_consoleArea.append(text);
	      }
	    });
	  }

	  public OutputStream getRedirectedSystemStreams() {
	    OutputStream out = new OutputStream() {
	      @Override
	      public void write(int b) throws IOException {
	        updateTextArea(String.valueOf((char) b));
	      }

	      @Override
	      public void write(byte[] b, int off, int len) throws IOException {
	        updateTextArea(new String(b, off, len));
	      }

	      @Override
	      public void write(byte[] b) throws IOException {
	        write(b, 0, b.length);
	      }
	    };

	    return out;
	  }
}
